class Event {
  constructor(){
    this._evtObjs = {}
  }
  on(key,handler,_once){
    if (!this._evtObjs[key]) {
      this._evtObjs[key] = [];
    }
    this._evtObjs[key].push({
      handler: handler,
      once: _once
    })
    return ()=>{
      this.off(key,handler)
    }
  }
  off(key,handler){
    let types;
    if(key){
      types = [key]
    }else{
      types = object.keys(this._evtObjs)
    }
    types.forEach((type)=>{
      if(!handler){
        this._evtObjs[type] = []
      }else{
        let handlers = this._evtObjs[type] || [],
            nextHandlers = []
        handlers.forEach((evtObj)=>{
          if(evtObj.handler !== handler){
            nextHandlers.push(evtObj)
          }
        })
        this._evtObjs[type] = nextHandlers
      }
    })
    return this
  }
  emit(evtType){
    let args = Array.prototype.slice.call(arguments, 1)
    let handlers = this._evtObjs[evtType] || [];
    handlers.forEach(function (evtObj) {
      if (evtObj.once && evtObj.called) return
      evtObj.called = true
      try {
        evtObj.handler && evtObj.handler.apply(null, args);
      } catch(e) {
        console.error(e.stack || e.message || e)
      }
    })
  }
}
let $event = new Event()
module.exports = {
  $event
}